package com.jiazhong.config;

/*
@Date:2025/6/17
*/


import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 核心功能：Spring MVC 请求日志拦截器（记录请求全生命周期信息）
 * 设计目标：
 * - 监控请求处理耗时
 * - 记录请求基础信息（路径、IP）
 * - 传递自定义消息到视图
 * - 捕获请求异常信息
 * 调试提示：可通过日志级别调整（如改为SLF4J）替代System.out输出
 */
// 1. 标记为Spring组件（自动扫描注册到容器）
@Component
public class LoggingInterceptor implements HandlerInterceptor {

    /**
     * 前置处理：请求到达Controller前的拦截点（关键控制节点）
     * 执行时机：DispatcherServlet调用HandlerMapping确定Handler后，执行HandlerAdapter前
     * 返回值：true（允许继续执行）/false（中断请求，后续拦截器和Controller不再执行）
     */
    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) {
// 【核心逻辑1】记录请求开始时间（存储到Request作用域，供后续阶段使用）
// 使用Long类型存储时间戳（毫秒级），避免类型转换错误
        request.setAttribute("startTime", System.currentTimeMillis());

// 【核心逻辑2】输出请求基础信息（调试用）
// getRequestURI()：获取请求路径（不包含域名和端口，如"/user/login"）
        System.out.println("【前置拦截】请求路径: " + request.getRequestURI());
// getRemoteAddr()：获取客户端IP（注意：经过反向代理时可能需要X-Forwarded-For头）
        System.out.println("【前置拦截】客户端IP: " + request.getRemoteAddr());

// 【控制逻辑】返回true表示放行请求，继续执行后续拦截器和Controller
// 若返回false：当前拦截器及后续拦截器不再执行，Controller也不会处理
        return true;
    }

    /**
     * 后置处理：Controller执行完成但视图未渲染前的拦截点
     * 执行时机：HandlerAdapter调用Handler方法后，视图解析前
     * 典型用途：修改ModelAndView数据、记录Controller执行结果
     */
    @Override
    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response,
                           Object handler,
                           ModelAndView modelAndView) {
// 【核心逻辑1】获取响应状态码（兼容不同Servlet版本）
// 使用response.getStatus()替代直接访问字段（确保兼容性）
        System.out.println("【后置处理】响应状态: " + response.getStatus());

// 【核心逻辑2】向视图传递自定义消息（示例：演示ModelAndView操作）
// 检查modelAndView是否为null（避免空指针异常）
        if (modelAndView != null) {
// 向视图添加属性（前端可通过${interceptorMsg}获取）
            modelAndView.addObject("interceptorMsg", "来自拦截器的消息");
        }
    }

    /**
     * 完成处理：整个请求生命周期结束后的拦截点（资源清理/统计）
     * 执行时机：DispatcherServlet渲染视图后，准备返回响应前
     * 典型用途：统计请求耗时、记录异常信息、释放资源
     */
    @Override
    public void afterCompletion(HttpServletRequest request,
                                HttpServletResponse response,
                                Object handler,
                                Exception ex) {
// 【核心逻辑1】计算请求耗时（从preHandle记录的startTime到当前时间）
// 从Request作用域获取startTime（需处理可能的null值）
        Object startTimeObj = request.getAttribute("startTime");
        if (startTimeObj != null) {
// 显式类型转换（确保类型安全，避免ClassCastException）
            long startTime = (Long) startTimeObj;
// 计算耗时（当前时间戳 - 开始时间戳）
            long duration = System.currentTimeMillis() - startTime;
            System.out.println("【完成处理】请求耗时: " + duration + "ms");
        } else {
// 异常情况处理（理论上不会触发，除非preHandle未执行或被中断）
            System.out.println("【完成处理】未找到开始时间标记");
        }

// 【核心逻辑2】记录请求异常信息（捕获Controller或视图渲染阶段的异常）
        if (ex != null) {
// 输出异常信息（生产环境建议记录到日志系统如Logback）
            System.out.println("【异常信息】: " + ex.getMessage());
// 可扩展：记录完整堆栈（ex.printStackTrace()）或发送告警
        }
    }
}